﻿using Daemon.Model;
using Microsoft.AspNetCore.Mvc;
using Daemon.Repository.Contract;
using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Daemon.Common;
using System.Linq;
using System;
using MySqlX.XDevAPI.Common;
using System.Collections.Generic;
using System.Net;
namespace DaemonAPI
{
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class DashboardController : BaseApiController
    {
        private readonly IBedInfoRepository _bedInfoRepository;

        private readonly IHMPatientDetailRepository _hmPatientDetailRepository;

        private readonly ICMPatientDetailRepository _cMPatientDetailRepository;

        private readonly IChargeDailyRepository _chargeDailyRepository;

        private readonly IHMFareDetailRepository _hMFareDetailRepository;

        private readonly ICMFareDetailRepository _cMFareDetailRepository;

        private readonly IIMItemKindRepository _iMItemKindRepository;

        private readonly ICMAdviceRepository _cMAdviceRepository;

        public DashboardController(IChargeDailyRepository chargeDailyRepository,
        IBedInfoRepository bedInfoRepository,
        IHMPatientDetailRepository hMPatientDetailRepository,
        ICMPatientDetailRepository cMPatientDetailRepository,
        IHMFareDetailRepository hMFareDetailRepository,
        ICMFareDetailRepository cMFareDetailRepository,
        IIMItemKindRepository iMItemKindRepository,
        ICMAdviceRepository cMAdviceRepository)
        {
            _bedInfoRepository = bedInfoRepository;
            _hmPatientDetailRepository = hMPatientDetailRepository;
            _cMPatientDetailRepository = cMPatientDetailRepository;
            _chargeDailyRepository = chargeDailyRepository;
            _hMFareDetailRepository = hMFareDetailRepository;
            _cMFareDetailRepository = cMFareDetailRepository;
            _iMItemKindRepository = iMItemKindRepository;
            _cMAdviceRepository = cMAdviceRepository;
        }

        [HttpGet]
        [Route("")]
        public ResultModel GetAreaMapRightData(int dataType)
        {
            var (compareStartDate, compareEndDate) = GetCompareDate(dataType);
            var cmFareDetails = _cMFareDetailRepository.FindAll().Where(r => r.CreateTime >= compareStartDate && r.CreateTime <= compareEndDate).Sum(r => r.Cash);
            var cmAdvices = _cMAdviceRepository.FindAll().Where(r => r.CreateTime >= compareStartDate && r.CreateTime <= compareEndDate).Select(r => r.PrescribeCode).Distinct().Count();
            return new ResultModel() { _statusCode = (int)HttpStatusCode.OK, obj = new { faDetails = cmFareDetails.ToString("F2"), adviceQty = cmAdvices } };
        }

        [HttpGet]
        [Route("")]
        public ResultModel GetCurveChartData()
        {
            List<string> averageFare = new List<string>();
            List<string> averageHospitalizationDays = new List<string>();
            var currentYear = DateTime.Now.Year;
            for (int i = 1; i <= 12; i++)
            {
                averageFare.Add(GetEveryMonthAverageFare(currentYear, i));
                averageHospitalizationDays.Add(GetEveryMonthAverageHospitalizationDays(currentYear, i));
            }

            return new ResultModel() { _statusCode = (int)HttpStatusCode.OK, obj = new { averageFare, averageHospitalizationDays } };
        }

        [HttpGet]
        [Route("")]
        public ResultModel GetDashboardNumberByType(int dataType)
        {
            var (compareStartDate, compareEndDate) = GetCompareDate(dataType);
            var (patientUsedBed, bedUsageRate, averageHospitalizationDays, convertRate) = GetWeekBedUsageRate(dataType);
            var patientCount = _cMPatientDetailRepository.FindAll().Count(r => r.InTime >= compareStartDate && r.InTime <= compareEndDate);
            var hmFareDetails = _hMFareDetailRepository.FindAll().Where(r => r.CreateTime >= compareStartDate && r.CreateTime <= compareEndDate).Sum(r => r.Cash);
            var cmFareDetails = _cMFareDetailRepository.FindAll().Where(r => r.CreateTime >= compareStartDate && r.CreateTime <= compareEndDate).Sum(r => r.Cash);
            var fareTotal = (hmFareDetails + cmFareDetails).ToString("F2");
            return new ResultModel() { _statusCode = (int)HttpStatusCode.OK, obj = new { bedUsageRate, patientUsedBed, patientCount, fareTotal, averageHospitalizationDays, convertRate } };
        }

        [HttpGet]
        [Route("")]
        public ResultModel GetPieChartDataByType(int dataType)
        {
            var (compareStartDate, compareEndDate) = GetCompareDate(dataType);
            var targetPatients = _cMPatientDetailRepository.FindAll().Count(r => r.InTime >= compareStartDate && r.InTime <= compareEndDate && r.Birthday < DateTime.Now.AddYears(-35));
            var nonTargetPatients = _cMPatientDetailRepository.FindAll().Count(r => r.InTime >= compareStartDate && r.InTime <= compareEndDate && r.Birthday >= DateTime.Now.AddYears(-35));
            return new ResultModel() { _statusCode = (int)HttpStatusCode.OK, obj = new List<PieData>() { new PieData() { type = "35岁以上患者占比", value = targetPatients, color = "#20b9cf" }, new PieData() { type = "35岁以下患者占比", value = nonTargetPatients, color = "#2089cf" }, new PieData() { type = "贫困救助患者", value = 10, color = "#2089cf" }, new PieData() { type = "非贫困救助患者", value = 70, color = "#205bcf" } } };
        }

        [HttpGet]
        [Route("")]
        public ResultModel GetIncomeByType(int dataType)
        {
            var (compareStartDate, compareEndDate) = GetCompareDate(dataType);
            var cTypes = _iMItemKindRepository.FindAll().Where(r => r.Name == "中药费").Select(r => (Int32)r.Code).ToList();
            Console.WriteLine(string.Join(',', cTypes));
            var outTypes = _iMItemKindRepository.FindAll().Where(r => r.Name == "西药费").Select(r => (Int32)r.Code).ToList();
            var cIncomeOne = _cMFareDetailRepository.FindAll().Where(r => r.ChargeTime >= compareStartDate && r.ChargeTime <= compareEndDate && cTypes.Contains(r.KindCode1)).AsEnumerable().Sum(r => r.Cash);
            var query = _hMFareDetailRepository.FindAll().Where(r => r.CreateTime >= compareStartDate && r.CreateTime <= compareEndDate && cTypes.Contains(r.KindCode2)).AsEnumerable();
            var cIncomeTwo = _hMFareDetailRepository.FindAll().Where(r => r.CreateTime >= compareStartDate && r.CreateTime <= compareEndDate && cTypes.Contains(r.KindCode2)).AsEnumerable().Sum(r => r.Cash);
            var xIncomeOne = _cMFareDetailRepository.FindAll().Where(r => r.ChargeTime >= compareStartDate && r.ChargeTime <= compareEndDate && outTypes.Contains(r.KindCode1)).AsEnumerable().Sum(r => r.Cash);
            var xIncomeTwo = _hMFareDetailRepository.FindAll().Where(r => r.CreateTime >= compareStartDate && r.CreateTime <= compareEndDate && outTypes.Contains(r.KindCode2)).AsEnumerable().Sum(r => r.Cash);
            return new ResultModel() { _statusCode = (int)HttpStatusCode.OK, obj = new List<ColumnData>() { new ColumnData() { type = "", detail = "中药", value = Convert.ToDecimal((cIncomeOne + cIncomeTwo).ToString("F2")) }, new ColumnData() { type = "", detail = "西药", value = Convert.ToDecimal((xIncomeOne + xIncomeTwo).ToString("F2")) } } };
        }

        private string GetEveryMonthAverageHospitalizationDays(int year, int month)
        {
            var (firstStartDate, firstEndDate) = GetMonthDate(DateTime.Now.Year, month);
            //获取每个月住院的人数
            var patientUsed = _hmPatientDetailRepository.FindAll().Where(r => r.InTime >= firstStartDate && r.InTime <= firstEndDate).ToList();
            int bedUsed = 0;
            patientUsed.ForEach(item =>
           {
               TimeSpan difference = TimeSpan.FromDays(0);
               if (item.OutTime > firstEndDate || item.OutTime == new DateTime(1900, 1, 1, 0, 0, 0, 0))
               {
                   difference = firstEndDate - item.InTime;
               }
               else
               {
                   difference = item.OutTime - item.InTime;
               }

               bedUsed += difference.Days;
           });

            return patientUsed.Count() == 0 ? "0" : ((decimal)bedUsed / patientUsed.Count()).ToString("F2");
        }

        private string GetEveryMonthAverageFare(int year, int month)
        {
            var (firstStartDate, firstEndDate) = GetMonthDate(DateTime.Now.Year, month);
            //获取每个月住院的人数
            var patientUsed = _hmPatientDetailRepository.FindAll().Where(r => r.InTime >= firstStartDate && r.InTime <= firstEndDate).Count();
            //获取每个月住院花的费用
            var hospitalizationFare = _hMFareDetailRepository.FindAll().Where(r => r.CreateTime >= firstStartDate && r.CreateTime <= firstEndDate).Sum(r => r.Cash);
            return patientUsed == 0 ? "0" : ((decimal)hospitalizationFare / patientUsed).ToString("F2");
        }

        private (DateTime startDate, DateTime endDate) GetMonthDate(int year, int month)
        {
            int dayCount = DateTime.DaysInMonth(year, month);
            var firstDayOfMonth = new DateTime(year, month, 1, 0, 0, 0);
            var endDayOfMonth = new DateTime(year, month, dayCount, 23, 59, 59);
            return (firstDayOfMonth, endDayOfMonth);
        }

        private (int patientUsedBed, string bedUsageRate, string averageHospitalizationDays, string convertRate) GetWeekBedUsageRate(int dataType)
        {
            var (compareStartDate, compareEndDate) = GetCompareDate(dataType);
            var totalDays = ((TimeSpan)(compareEndDate - compareStartDate)).Days;
            var leavePersons = _hmPatientDetailRepository.FindAll().Count(r => r.OutTime >= compareStartDate && r.OutTime <= compareEndDate);
            var patientUsed = _hmPatientDetailRepository.FindAll().Where(r => r.InTime >= compareStartDate && r.InTime <= compareEndDate).ToList();
            int bedUsed = 0;
            patientUsed.ForEach(item =>
            {
                TimeSpan difference = TimeSpan.FromDays(0);
                if (item.OutTime > compareEndDate || item.OutTime == new DateTime(1900, 1, 1, 0, 0, 0, 0))
                {
                    difference = compareEndDate - item.InTime;
                }
                else
                {
                    difference = item.OutTime - item.InTime;
                }

                bedUsed += difference.Days;
            });
            var bedCount = _bedInfoRepository.FindAll().Count();
            var bedUsageRate = ((decimal)bedUsed * 100 / (bedCount * totalDays)).ToString("F2") + "%";
            var averageHospitalizationDays = leavePersons == 0 ? "0" : (bedUsed / leavePersons).ToString("F2");
            var convertRate = ((decimal)leavePersons * 100 / (bedCount)).ToString("F2") + "%";
            var patientUsedBed = _hmPatientDetailRepository.FindAll().Count(r => r.InTime >= compareStartDate && r.OutTime <= compareEndDate);
            return (patientUsedBed, bedUsageRate, averageHospitalizationDays, convertRate);
        }

        private DateTime GetStartOfWeek(DateTime dt, DayOfWeek startOfWeek)
        {
            int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
            return dt.AddDays(-1 * diff).Date;
        }

        private (DateTime startDate, DateTime endDate) GetCompareDate(int dataType)
        {
            DateTime compareStartDate = DateTime.Now; // 假设当前日期为今天
            DateTime compareEndDate = DateTime.Now;
            switch (dataType)
            {
                case 1:
                    compareStartDate = GetStartOfWeek(compareStartDate, DayOfWeek.Monday);  //本周周一  
                    compareEndDate = compareStartDate.AddDays(6);  //本周周日  
                    break;
                case 2:
                    compareStartDate = compareStartDate.AddDays(1 - compareStartDate.Day);
                    compareEndDate = compareEndDate.AddMonths(1).AddDays(-1);  //本月月末  
                    break;
                case 3:
                    compareStartDate = new DateTime(compareStartDate.Year, 1, 1);
                    compareEndDate = new DateTime(compareEndDate.Year, 12, 31);  //本年年末  
                    break;
            }

            return (compareStartDate, compareEndDate.AddHours(23).AddMinutes(59).AddSeconds(59));
        }

        private class PieData
        {
            public string type { get; set; }

            public int value { get; set; }

            public string color { get; set; }
        }

        private class ColumnData
        {
            public string type { get; set; }

            public string detail { get; set; }

            public decimal value { get; set; }
        }
    }
}
